#include"../common/net.hpp"
#include"../common/message.hpp"
#include<set>
#include<unordered_map>

namespace bitRPC {
    namespace server {
        class ProviderManager {
            public:
                using ptr = std::shared_ptr<ProviderManager>;
                struct Provider {
                    using ptr = std::shared_ptr<Provider>;
                    std::mutex _mutex;
                    BaseConnection::ptr conn;
                    Address host;
                    std::vector<std::string> methods;
                    Provider(const BaseConnection::ptr &c, const Address &h):
                        conn(c), host(h){}
                    void appendMethod(const std::string &method) {
                        std::unique_lock<std::mutex> lock(_mutex);
                        methods.emplace_back(method);
                    }
                };
                //当一个新的服务提供者进行服务注册的时候调用
                void addProvider(const BaseConnection::ptr &c, const Address &h, const std::string &method) {
                    Provider::ptr provider;
                    //查找连接所关联的服务提供者对象，找到则获取，找不到则创建，并建立关联
                    {
                        std::unique_lock<std::mutex> lock(_mutex);
                        auto it = _conns.find(c);
                        if (it != _conns.end()) {
                            provider = it->second;
                        }else {
                            provider = std::make_shared<Provider>(c, h);
                            _conns.insert(std::make_pair(c, provider));
                        }
                        //method方法的提供主机要多出一个，_providers新增数据
                        auto &providers = _providers[method];
                        providers.insert(provider);
                    }
                    //向服务对象中新增一个所能提供的服务名称
                    provider->appendMethod(method);
                }
                //当一个服务提供者断开连接的时候，获取他的信息--用于进行服务下线通知
                Provider::ptr getProvider(const BaseConnection::ptr &c) {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end()) {
                        return it->second;
                    }
                    return Provider::ptr();
                }
                //当一个服务提供者断开连接的时候，删除它的关联信息
                void delProvider(const BaseConnection::ptr &c) {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it == _conns.end()) {
                        //当前断开连接的不是一个服务提供者
                        return;
                    }
                    //如果是提供者，看看提供了什么服务，从服务者提供信息中删除当前服务提供者
                    for (auto & method : it->second->methods) {
                        auto &providers = _providers[method];
                        providers.erase(it->second);
                    }
                    //删除连接与服务提供者的关联关系
                    _conns.erase(it);
                }
                std::vector<Address> methodHosts(const std::string &method) {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _providers.find(method);
                    if (it == _providers.end()) {
                        return std::vector<Address>();
                    }
                    std::vector<Address> result;
                    for (auto &provider : it->second) {
                        result.push_back(provider->host);
                    }
                    return result;
                }
            private:
                std::mutex _mutex;
                std::unordered_map<std::string, std::set<Provider::ptr>> _providers;
                std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
        };
        class DiscoverManager{
            public:
                using ptr=std::shared_ptr<DiscoverManager>;

                struct Discover
                {
                    using ptr=std::shared_ptr<Discover>;
                    std::mutex _mutex;
                    std::vector<std::string> _method;//发现过的服务名称
                    BaseConnection::ptr _conn;//发现者关联客户端连接
                    Discover(const BaseConnection::ptr& conn):_conn(conn){}
                    void appendMethod(const std::string& method)
                    {
                        std::unique_lock<std::mutex> lock(_mutex);
                        _method.push_back(method);
                    }
                };
                //每次客户端进行服务发现的时候新增发现者，新增服务名称
                Discover::ptr addDiscover(const BaseConnection::ptr& conn,const std::string& method)
                {
                    Discover::ptr discover;
                    {
                        std::unique_lock<std::mutex> lock(_mutex);
                        auto it =_conn.find(conn);
                        if(it==_conn.end())
                        {
                            discover=std::make_shared<Discover>(conn);
                            _conn.insert(std::make_pair(conn,discover));
                        }else{
                            discover=it->second;
                        }
                        auto &discovers=_discover[method];
                        discovers.insert(discover);

                    }
                    discover->appendMethod(method);
                    return discover;

                }
                //发现者客户端断开连接时，找到发现者，删除该数据信息
                Discover::ptr delDiscover(const BaseConnection::ptr& conn)               //当一个发现者进行注销
                {
                    
                        std::unique_lock<std::mutex> lock(_mutex);
                        auto it =_conn.find(conn);
                        if(it==_conn.end())
                        {
                            return Discover::ptr();
                        }
                        for (auto &method : it->second->_method){
                        auto discoverers = _discover[method];
                        discoverers.erase(it->second);
                        }
                    _conn.erase(it);
                }
                //服务上线通知
                void onlineNotify(const std::string &method, const Address &host) {
                    return notify(method, host, ServiceOptype::SERVICE_ONLINE);
                }
                //当有一个服务提供者断开连接，则进行下线通知
                void offlineNotify(const std::string &method, const Address &host) {
                    return notify(method, host, ServiceOptype::SERVICE_OFFLINE);
                }
            private:
                void notify(const std::string& method,const Address& host,ServiceOptype serviceOptype)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it=_discover.find(method);
                    if(it==_discover.end())
                    {
                        // 代表没有这个发现者
                        return ;
                    }
                    auto msg=bitRPC::MessageFactory::create<ServiceReqest>();
                    msg->setMType(MType::REQ_SERVICE);
                    msg->setId(UUID::uuid());
                    msg->setMethod(method);
                    msg->setHost(host);
                    msg->setOptype(serviceOptype);
                     for (auto &discoverer : it->second) {
                        discoverer->_conn->send(msg);
                    }
                }
            private:
                std::unordered_map<std::string,std::set<Discover::ptr>> _discover;
                std::unordered_map<BaseConnection::ptr,Discover::ptr> _conn;
                std::mutex _mutex;
                
        };
        class PDManage{
            public:
                using ptr=std::shared_ptr<PDManage>;
                PDManage():_provider(std::make_shared<ProviderManager>())
                ,_discover(std::make_shared<DiscoverManager>())
                {}
                void onServiceRequest(const BaseConnection::ptr con,const ServiceReqest::ptr &msg)
                {
                    auto optype=msg->optype();
                    if(optype==ServiceOptype::SERVICE_REGISTER)
                    {
                        //服务注册
                        _provider->addProvider(con,msg->host(),msg->method());
                        _discover->onlineNotify(msg->method(),msg->host());
                        return rigstryResponse(con,msg);
                    }else if(msg->optype()==ServiceOptype::SERVICE_DISCOVERY)
                    {
                        //服务发现
                        _discover->addDiscover(con,msg->method());
                        return discoverResponse(con,msg);
                    }else{
                        ELOG("收到服务操作请求，但是操作类型错误！");
                        return errorResponse(con,msg);
                    }
                    
                }
                void onConnShutdown(const BaseConnection::ptr& con)
                {
                    auto provider=_provider->getProvider(con);
                    if(provider.get()!=nullptr)
                    {
                        //是服务提供者，要进行下线通知
                        for(auto &method:provider->methods)
                        {
                            _discover->offlineNotify(method,provider->host);
                        }
                        _provider->delProvider(con);
                    }
                    _discover->delDiscover(con);
                }
            private:
                void errorResponse(const BaseConnection::ptr& conn,const ServiceReqest::ptr& msg)
                {
                    
                    auto msg_rsp=MessageFactory::create<ServiceResponse>();
                    msg_rsp->setMType(MType::RES_SERVICE);
                    msg_rsp->setId(msg->Rid());
                    msg_rsp->setOptype(ServiceOptype::SERVICE_UNKNOW);
                    msg_rsp->setRCode(Rcode::RCODE_NOT_FOUND_SERVICE);
                    conn->send(msg_rsp);
                }

                void rigstryResponse(const BaseConnection::ptr& conn,const ServiceReqest::ptr& msg)
                {
                    auto msg_rsp=MessageFactory::create<ServiceResponse>();
                    msg_rsp->setMType(MType::RES_SERVICE);
                    msg_rsp->setId(msg->Rid());
                    msg_rsp->setOptype(ServiceOptype::SERVICE_REGISTER);
                    msg_rsp->setRCode(Rcode::RCODE_OK);
                    conn->send(msg_rsp);
                }
                void discoverResponse(const BaseConnection::ptr& conn,const ServiceReqest::ptr& msg)
                {
                    auto msg_rsp=MessageFactory::create<ServiceResponse>();
                    std::vector<Address> host=_provider->methodHosts(msg->method());
                    if(host.empty())
                    {
                        msg_rsp->setRCode(Rcode::RCODE_NOT_FOUND_SERVICE);
                    }else{
                        msg_rsp->setRCode(Rcode::RCODE_OK);
                    }
                    msg_rsp->setMType(MType::RES_SERVICE);
                    msg_rsp->setId(msg->Rid());
                    msg_rsp->setOptype(ServiceOptype::SERVICE_DISCOVERY);
                    conn->send(msg_rsp);
                }
            private:
                ProviderManager::ptr _provider;
                DiscoverManager::ptr _discover;
            };
    }
    
}
